﻿using System;
using System.IO;
using System.Runtime.Serialization;
using Foundation;
using Microsoft.Win32;

namespace Poet.ViewModels
{
    [DataContract]
    public class SettingsViewModel : ViewModel
    {
        private static readonly string RunRegistryKey =
            Path.Combine(Registry.CurrentUser.ToString(), @"Software\Microsoft\Windows\CurrentVersion\Run\");

        private static readonly string RunRegistryKeyCommon =
            Path.Combine(Registry.LocalMachine.ToString(), @"Software\Microsoft\Windows\CurrentVersion\Run\");

        public SettingsViewModel()
        {
            Initialize();
        }

        public bool AutorunShortcut
        {
            get { return Manage(Environment.SpecialFolder.Startup); }
            set { Manage(Environment.SpecialFolder.Startup, value); }
        }

        public bool AutorunShortcutCommon
        {
            get { return Manage(Environment.SpecialFolder.CommonStartup); }
            set { Manage(Environment.SpecialFolder.CommonStartup, value); }
        }

        public bool AutorunRegistryKey
        {
            get { return Manage(RunRegistryKey); }
            set { Manage(RunRegistryKey, value); }
        }

        public bool AutorunRegistryKeyCommon
        {
            get { return Manage(RunRegistryKeyCommon); }
            set { Manage(RunRegistryKeyCommon, value); }
        }

        public bool DesktopLink
        {
            get { return Manage(Environment.SpecialFolder.Desktop); }
            set { Manage(Environment.SpecialFolder.Desktop, value); }
        }

        public bool DesktopDirectoryLink
        {
            get { return Manage(Environment.SpecialFolder.DesktopDirectory); }
            set { Manage(Environment.SpecialFolder.DesktopDirectory, value); }
        }

        public bool CommonDesktopDirectoryLink
        {
            get { return Manage(Environment.SpecialFolder.CommonDesktopDirectory); }
            set { Manage(Environment.SpecialFolder.CommonDesktopDirectory, value); }
        }

        [DataMember]
        public bool SpellCheckTeaching
        {
            get { return Get(() => SpellCheckTeaching, true); }
            set { Set(() => SpellCheckTeaching, value); }
        }

        [DataMember]
        public bool WordCompleteTeaching
        {
            get { return Get(() => SpellCheckTeaching, true); }
            set { Set(() => SpellCheckTeaching, value); }
        }

        private static bool Manage(Environment.SpecialFolder folder, bool? set = null, string name = null, string target = null)
        {
            target = target ?? InstanceManager.ExecutableFilePath;
            name = name ?? Path.GetFileNameWithoutExtension(target) ?? string.Empty;
            name = name.EndsWith(Link.ShortcutExtension) ? Path.GetFileNameWithoutExtension(name) : name;
            var folderPath = Environment.GetFolderPath(folder);
            var path = Path.Combine(folderPath, name ?? string.Empty);

            var basePath = path;
            for (var i = 1; i < long.MaxValue; i++)
            {
                path = path + Link.ShortcutExtension;
                if (!File.Exists(path) || Link.Exists(Link.Kind.Shortcut, path, target)) break;
                path = basePath + " (" + i + ")";
            }

            switch (set)
            {
                case false:
                    Link.Delete(Link.Kind.Shortcut, path, target);
                    return false;
                case true:
                    Link.Create(Link.Kind.Shortcut, path, target);
                    return true;
                default:
                    var exists = Link.Exists(Link.Kind.Shortcut, path, target);
                    return exists;
            }  
        }

        private static bool Manage(string registryKey, bool? set = null, string name = null, string target = null)
        {
            target = target ?? InstanceManager.ExecutableFilePath;
            name = name ?? Path.GetFileNameWithoutExtension(target) ?? string.Empty;
            var linkPath = Path.Combine(registryKey, name);

            var baseName = name;
            for (var i = 0; i < long.MaxValue; i++)
            {
                var value = Registry.GetValue(registryKey, name, null);
                if (value == null || Equals(value, target)) break;
                name = baseName + i;
            }

            switch (set)
            {
                case false:
                    Link.Delete(Link.Kind.RegistryValue, linkPath, target);
                    return false;
                case true:
                    Link.Create(Link.Kind.RegistryValue, linkPath, target);
                    return true;
                default:
                    var exists = Link.Exists(Link.Kind.RegistryValue, linkPath, target);
                    return exists;
            } 
        }

        [OnDeserialized]
        private void Initialize(StreamingContext context = default(StreamingContext))
        {
            ApplicationClosing += () => this.TrySerializeDataContract();
            this[() => AutorunShortcut].PropertyChanged += (sender, args) => RaisePropertyChangedEvent(() => AutorunShortcut);
            this[() => AutorunShortcutCommon].PropertyChanged += (sender, args) => RaisePropertyChangedEvent(() => AutorunShortcut);
            this[() => AutorunRegistryKey].PropertyChanged += (sender, args) => RaisePropertyChangedEvent(() => AutorunShortcut);
            this[() => AutorunRegistryKeyCommon].PropertyChanged += (sender, args) => RaisePropertyChangedEvent(() => AutorunShortcut);
        }
    }
}